package com.xrosstools.xunit.editor.model;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UnitNodePanel implements UnitNodeContainer {
	private CompositeUnitNode parent;
	private List<UnitNode> units = new ArrayList<UnitNode>();
	private int UNLIMITED_SIZE = -1;
	private int fixedSize = UNLIMITED_SIZE;
	private boolean vertical = true;
	
	private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
	
	public UnitNodePanel(CompositeUnitNode parent){
		this(parent, true);
	}

	public UnitNodePanel(CompositeUnitNode parent, boolean vertical){
		this.parent = parent;
		this.vertical = vertical;
	}
	
	public UnitNodePanel(CompositeUnitNode parent, int fixedSize){
		this(parent, true);
		this.fixedSize = fixedSize;
		init();
	}

	private void init(){
		if(fixedSize == UNLIMITED_SIZE)
			return;
		
		for(int i = 0; i< fixedSize; i++)
			units.add(null);
	}
	
	private void firePropertyChange(String propertyName){
		listeners.firePropertyChange(propertyName, null, null);
	}
	
	public boolean isVertical(){
		return vertical;
	}

	public int size(){
		int i = 0;
		for(UnitNode unit:units)
			i += (unit == null ? 0 : 1);
		return i;
	}
	
	public int indexOf(UnitNode unit){
		return units.indexOf(unit);
	}
	
	public boolean contains(UnitNode unit){
		return units.contains(unit);
	}
	
	public UnitNode get(int index){
		return units.get(index);
	}
	
	public List<UnitNode> getAll(){
		List<UnitNode> tmpUnits = new ArrayList<UnitNode>();
		for(UnitNode unit:units)
			if(unit != null)
				tmpUnits.add(unit);

		return tmpUnits;
	}

	public boolean isFixedSize(){
		return fixedSize != UNLIMITED_SIZE;
	}

	public int getFixedSize(){
		return fixedSize;
	}

	public boolean checkDropAllowed(int index){
		if(fixedSize == UNLIMITED_SIZE)
			return true;
		
		return fixedSize != size();
	}
	
	public boolean add(int index, UnitNode unit) {
		if(!checkDropAllowed(index))
			return false;
		
		if(isFixedSize()){
			if(index < fixedSize && units.get(index) == null)
				set(index, unit);
			else if(index == fixedSize && units.get(0) != null)
				set(1, unit);
			else if(index == 1 && units.get(0) == null)
				set(0, unit);
			else
				return false;
		}
		else
			units.add(index, unit);
		
		forceRefresh();
		parent.unitAdded(index, unit);
		firePropertyChange(PROP_NODE);
		return true;
	}
	
	public boolean add(UnitNode unit){
		if(!checkDropAllowed(size()))
			return false;

		if(!isFixedSize())
			return add(size(), unit);
		
		if(units.get(0) == null)
			set(0, unit);
		else
			set(1, unit);
		
		return true;
	}
	
	public void set(int index, UnitNode unit){
		if(!checkDropAllowed(index))
			return;
		
		units.set(index, unit);
		parent.unitSet(index, unit);
		firePropertyChange(PROP_NODE);
	}
	
	public void remove(UnitNode unit) {
		if(!units.contains(unit))
			return;
		
		if(isFixedSize())
			units.set(indexOf(unit), null);
		else
			units.remove(unit);
		
		parent.unitRemoved(unit);
		firePropertyChange(PROP_NODE);
	}
	
	public void move(int newIndex, UnitNode unit){
		// For non fixed size or full fixed size
		if(!isFixedSize()){
			UnitNode after = newIndex < units.size() ? units.get(newIndex) : null;
			units.remove(unit);
			units.add(after == null ? units.size() : units.indexOf(after), unit);
		}else{
			// just switch. should only be the bi-branch case
			Collections.reverse(units);
		}
		
		forceRefresh();
		parent.unitMoved(unit);
		firePropertyChange(PROP_NODE);
	}
	
	private void forceRefresh(){
		if(!isFixedSize())
			return;
		
		List<UnitNode> tmpUnits = new ArrayList<UnitNode>(units);
		// Force
		for(int i = 0; i < fixedSize; i++)
			units.set(i, null);
		firePropertyChange(PROP_NODE);
		for(int i = 0; i < fixedSize; i++)
			units.set(i, tmpUnits.get(i));
		firePropertyChange(PROP_NODE);
	}
	
	public void addPropertyChangeListener(PropertyChangeListener lilistener) {
		listeners.addPropertyChangeListener(lilistener);
	}
	
	public void removePropertyChangeListener(PropertyChangeListener lilistener) {
		listeners.removePropertyChangeListener(lilistener);
	}
}

